package com.tzh.proxy;

import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.ModelType;
import org.mybatis.generator.config.TableConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;


public class ContextCGlibProxy implements MethodInterceptor {

    private static Connection connection = null;

    private static final Logger log = LoggerFactory.getLogger(ContextCGlibProxy.class);


    private Object targetObject;

    public <T> T CreateContextProxyObject(Context t) {
        targetObject = t;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(t.getClass());
        enhancer.setCallback(this);
        return (T) enhancer.create(new Class[]{ModelType.class}, new Object[]{ModelType.FLAT});
    }


    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        if (method.getName().equals("generateFiles")) {
            System.out.println("拦截中");
            Context context = (Context) targetObject;
            if (context.getId().toUpperCase().equals("ORACLE")) {
                log.info("oracle数据库");
                setOracleTableProperties(context);
            }
            if (context.getId().toUpperCase().equals("MYSQL")) {
                log.info("Mysql数据库");
                setMysqlTableProperties(context);

            }
        }
        obj = method.invoke(targetObject, args);
        return obj;
    }

    private void setMysqlTableProperties(Context context) {
        List<TableConfiguration> config = context.getTableConfigurations();
        config.stream().forEach(table -> {
            try {
                if (connection == null) {
                    setConnection(context);
                }
                String dbName = connection.getCatalog();
                String tableName = table.getTableName().toUpperCase();
                PreparedStatement ps = null;
                if ("%".equals(tableName)) {
                    String sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema=? ";
                    ps = connection.prepareStatement(sql);
                    ps.setString(1, dbName);
                    setTableName(table, ps);
                    sql = "SELECT table_name,column_comment,COLUMN_NAME,data_type,ifnull(numeric_precision,character_maximum_length) data_length FROM INFORMATION_SCHEMA.Columns WHERE table_schema=?";
                    ps = connection.prepareStatement(sql);
                    ps.setString(1, dbName);
                    setColName(table, ps);

                } else {
                    String sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema=? and table_name=?";
                    ps.setString(1, dbName);
                    ps.setString(2, tableName);
                    ps = connection.prepareStatement(sql);
                    setTableName(table, ps);
                    sql = "SELECT table_name,column_comment,COLUMN_NAME,data_type,ifnull(numeric_precision,character_maximum_length) data_length FROM INFORMATION_SCHEMA.Columns WHERE table_schema=? AND table_name=?";
                    ps = connection.prepareStatement(sql);
                    ps.setString(1, dbName);
                    ps.setString(2, tableName);
                    setColName(table, ps);
                }
            } catch (SQLException | ClassNotFoundException e) {
                e.printStackTrace();
            }
            System.out.println(table.getTableName());
        });
    }


    private void setConnection(Context context) throws SQLException, ClassNotFoundException {
        String url = context.getJdbcConnectionConfiguration().getConnectionURL();
        String className = context.getJdbcConnectionConfiguration().getDriverClass();
        String userName = context.getJdbcConnectionConfiguration().getUserId();
        String password = context.getJdbcConnectionConfiguration().getPassword();
        Class.forName(className);
        connection = DriverManager.getConnection(url, userName, password);
    }


    private void setOracleTableProperties(Context context) {
        List<TableConfiguration> config = context.getTableConfigurations();
        config.stream().forEach(table -> {
            try {
                if (connection == null) {
                    setConnection(context);
                }
                String sql = "select table_name ,comments TABLE_COMMENT " +
                        "from user_tab_comments where table_name = ?";
                PreparedStatement ps = connection.prepareStatement(sql);
                String tableName = table.getTableName().toUpperCase();
                ps.setString(1, tableName);
                setTableName(table, ps);
                sql = "select a.table_name,b.comments column_comment,a.column_name,a.DATA_TYPE,nvl(a.DATA_PRECISION,a.DATA_LENGTH) data_length,a.DATA_DEFAULT " +
                        "from dba_tab_columns a,user_col_comments b " +
                        "where a.column_name=b.column_name " +
                        "and a.TABLE_NAME = b.table_name " +
                        " and a.table_name = ?";
                ps = connection.prepareStatement(sql);
                ps.setString(1, tableName);
                setColName(table, ps);
            } catch (SQLException | ClassNotFoundException e) {
                e.printStackTrace();
            }
//            System.out.println(table.getTableName());
        });
    }


    private void setTableName(TableConfiguration table, PreparedStatement ps) throws SQLException {
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            String tName = rs.getString("table_name");
            String comments = rs.getString("table_comment");
            table.getProperties().setProperty(tName + ":comments", comments.replace("\\", "'\\'"));
        }
    }

    private void setColName(TableConfiguration table, PreparedStatement ps) throws SQLException {
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            String tName = rs.getString("table_name");
            String comments = rs.getString("column_comment");
            if (!StringUtils.isEmpty(comments)) {
                comments = comments.replace("\\", "'\\'");
                comments = comments.replace("\n", ",");
            }
            String columnName = rs.getString("column_name");
            String dataType = rs.getString("data_type");
            int dataLenght = rs.getInt("data_length");
            table.getProperties().setProperty(tName + ":" + columnName, dataType + ":" + dataLenght + ":" + comments);
        }
    }

}
